#include <algorithm>
#include <stdexcept>

#ifndef VECTOR_
#define VECTOR_

using std::max;

namespace _mg_inner {
template<typename T>
class vector_base {
	typedef T value_type;
protected:
	value_type* start;
	value_type* finish;
	value_type* end_of_store;

	vector_base(const vector_base & v, size_t initial_capacity) :
		start(new value_type[initial_capacity]), finish(start + v.size()),
				end_of_store(start + initial_capacity) {
		copy(v.start, v.finish, start);
	}

	vector_base(size_t size, value_type default_value, size_t initial_capacity) :
		start(new value_type[initial_capacity]), finish(start + size),
				end_of_store(start + initial_capacity) {
		fill(start, finish, default_value);
	}
public:
	size_t size() const {
		return size_t(finish - start);
	}

	~vector_base() {
		delete[] start;
	}
};
}

template<typename T>
class vector: protected _mg_inner::vector_base<T> {
	typedef T value_type;
protected:
	static const size_t increase_factor = 2;
	static const size_t default_capacity = 2;
public:
	using _mg_inner::vector_base<value_type>::start;
	using _mg_inner::vector_base<value_type>::finish;
	using _mg_inner::vector_base<value_type>::size;
	using _mg_inner::vector_base<value_type>::end_of_store;

	explicit vector(size_t size = 0, value_type default_value = value_type(),
			size_t initial_capacity = default_capacity) :
		_mg_inner::vector_base<value_type>(size, default_value, max(
				initial_capacity, size)) {
	}

	vector(const vector & v, size_t initial_capacity = 0) :
		_mg_inner::vector_base<value_type>(v, max(v.size(), initial_capacity)) {
	}

private:
	void swap(vector& v) {
		std::swap(v.start, start);
		std::swap(v.finish, finish);
		std::swap(v.end_of_store, end_of_store);
	}

public:
	vector& operator=(const vector& v) {
		vector<value_type> temp(v);
		swap(temp);
		return *this;
	}

	value_type& operator[](size_t index) const {
		return *(start + index);
	}

	value_type& at(size_t index) const {
		if (start + index >= finish) {
			throw std::out_of_range(":(");
		}
		return (*this)[index];
	}

	void reserve(size_t size) {
		if (start + size > finish) {
			vector<value_type> temp(*this, size);
			swap(temp);
		}
	}

	void push_back(const value_type& element) {
		if (finish == end_of_store) {
			reserve(size() * increase_factor);
		}
		*(finish++) = element;
	}
};

#endif /* VECTOR_ */
